package com.orange.smartcity.android.tools;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.Log;

public class ImageLoaderUtils
{
	private static final String TAG = "ImageLoader";

	private static final int QUEUE_MAX = 100;

	private final Context mContext;
	private final HashMap<String, SoftReference<Bitmap>> mSoftCache;
	private final String mCacheDir;
	private final LinkedHashMap<String, LoadTask> mTasks;
	private int mRunningTasks;

	public ImageLoaderUtils(Context context)
	{
		mContext = context;

		mTasks = new LinkedHashMap<String, LoadTask>();
		mRunningTasks = 0;
		mSoftCache = new HashMap<String, SoftReference<Bitmap>>();
		mCacheDir = mContext.getCacheDir().toString();
	}

	public boolean isImageLoaded(String url)
	{
		return (mSoftCache.containsKey(url));
	}

	public Bitmap loadImage(final String url, final ImageCallback callback)
	{
		Bitmap image = null;

		if (mSoftCache.containsKey(url)) {
			image = mSoftCache.get(url).get();
			Log.d(TAG, "SoftCached: " + url);
		}

		if (image == null) {
			image = cacheGet(url);
			if (image != null) {
				Log.d(TAG, "Cached: " + url);
				mSoftCache.put(url, new SoftReference<Bitmap>(image));
			}
		}

		if (image != null || callback == null) {
			return image;
		}

		if (!mTasks.containsKey(url)) {
			mTasks.put(url, new LoadTask(callback, url));
			checkQueue();
		}

		return null;
	}

	private void checkQueue()
	{
		if (mRunningTasks < QUEUE_MAX && mTasks.size() > 0) {
			Iterator<LoadTask> iterator = mTasks.values().iterator();

			while (mRunningTasks < QUEUE_MAX && iterator.hasNext()) {
				LoadTask task = iterator.next();

				if (task.getStatus() != AsyncTask.Status.RUNNING) {
					mRunningTasks++;
					task.execute();
					break;
				}
			}
		}
	}

	private synchronized Bitmap cacheGet(String url)
	{
		File file = getFileName(url);

		if (file.exists()) {
			Log.d(TAG, "Cache GET Hit");
			Bitmap bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
			if (bitmap != null) {
				return bitmap;
			}
		}

		return null;
	}

	private void cachePut(String url, Bitmap img)
	{
		File file = getFileName(url);

		try {
			file.createNewFile();
			FileOutputStream os = new FileOutputStream(file);
			img.compress(Bitmap.CompressFormat.PNG, 100, os);
			os.close();
		} catch (FileNotFoundException e) {
		} catch (IOException e) {
		}
	}

	private File getFileName(String url)
	{
		return new File(mCacheDir + "/" + Integer.toHexString(url.hashCode()) + ".png");
	}

	private class LoadTask extends AsyncTask<String, Void, Bitmap>
	{
		ImageCallback mCallback;
		String mUrl;

		public LoadTask(ImageCallback imageCallback, String url)
		{
			mCallback = imageCallback;
			mUrl = url;
		}

		@Override
		protected Bitmap doInBackground(String... urls)
		{
			try {
				return BitmapFactory.decodeStream(new URL(mUrl).openStream());
			} catch (MalformedURLException e) {
			} catch (IOException e) {
			}

			return null;
		}

		@Override
		protected void onPostExecute(Bitmap image)
		{
			mTasks.remove(mUrl);
			mRunningTasks--;

			checkQueue();

			if (image != null) {
				mSoftCache.put(mUrl, new SoftReference<Bitmap>(image));
				cachePut(mUrl, image);
				mCallback.onSuccess(mUrl, image);
			} else {
				mCallback.onFailure(mUrl);
			}
		}
	}

	public interface ImageCallback
	{
		public void onSuccess(String imageUrl, Bitmap image);

		public void onFailure(String imageUrl);
	}
}
